<?php

namespace seecms\controller;

use seecms\lib\builder\Page;
use seecms\lib\builder\PageParse;
use seecms\db\SeeDbException;
use seecms\See;
use seecms\lib\Operate;
use seecms\lib\Transfer;
use seecms\SeeException;
use seecms\SeeLang;

/**
 *资源控制器
 */
class Resource extends SeeBaseController
{
    /**
     * 表名称
     * @var string
     */
    protected $table_name = null;

    protected $dictionary_name = '';

    protected $template = 'public/index';

    /**
     * @throws SeeException
     */
    protected function db(): \seecms\db\SeeDbQuery
    {
        if (empty($this->table_name)) {
            throw new SeeException(static::class . ', table name is null');
        }

        return See::db()->table($this->table_name);
    }

    protected function pageTitle(): string
    {
        return '';
    }

    /**
     * 获取查询表达式
     * @return array
     */
    protected function queryExpress(): array
    {
        $query = $this->query();
        $params = See::request()->get() ?: [];
        return Transfer::pageQuery($query, $params);
    }

    /**
     * @return array|string
     * @throws SeeException|SeeDbException
     */
    public function index()
    {
        if (See::request()->isAjax()) {

            $where = $this->queryExpress();

            $data = $this->db()->order('id desc')->where($where)->paginate();

            return $this->success($this->columnFilter($data));
        }

        return See::view()->page($this->builder(), $this->template);
    }

    protected function columnFilter($data)
    {
        return $data;
    }

    /**
     * @return string
     * @throws SeeException
     */
    public function read(): string
    {
        $id = See::request()->param('id');

        $parse = PageParse::global($this->dictionary_name);

        $controls = $parse->controls($this->readControls());

        $data = $this->db()->find($id);

        foreach ($controls as $key => $control) {
            $control->setReadonly();
            $control->setDisabled();
            $control->setValue(null);
            $controls[$key] = $control;
            $name = $control->getName() ?? null;
            if (empty($name) || !isset($data[$name])) {
                continue;
            }
            $val = $data[$name];
            $control->setValue($val);
            $controls[$key] = $control;
        }

        return $this->view('public/control', [
            'id' => $id,
            'btn' => false,
            'controls' => $controls,
        ]);
    }

    /**
     * @return string|array
     */
    public function edit()
    {
        $id = See::request()->param('id');

        if (empty($id)) {
            return $this->fail(Operate::required());
        }

        $parse = new PageParse(SeeLang::instance()->global($this->dictionary_name));
        $controls = $parse->controls($this->controls());

        $data = See::db()->table($this->table_name)->find($id);

        foreach ($controls as $key => $control) {
            $name = $control->getName();
            if (empty($name)) {
                continue;
            }
            $val = $data[$name] ?? $control->getValue();
            $control->setValue($val);
            $controls[$key] = $control;
        }

        return $this->view('public/control', [
            'id' => $id,
            'btn' => true,
            'controls' => $controls,
            'action' => 'update',
        ]);
    }

    /**
     * @return array
     * @throws SeeDbException|SeeException
     */
    public function update(): array
    {
        $data = See::request()->post();

        if (empty($data)) {
            return $this->fail(Operate::saveParameterNull());
        }

        if (empty($data['id'] ?? '')) {
            return $this->fail(Operate::required());
        }

        // 返回的是更新条数
        $result = $this->db()->where('id', $data['id'])->update($data);

        return $this->success($result);
    }

    /**
     * @return string
     */
    public function create(): string
    {
        $parse = new PageParse(SeeLang::instance()->global($this->dictionary_name));
        $controls = $parse->controls($this->controls());

        return $this->view('public/control', [
            'controls' => $controls,
            'btn' => true,
            'action' => 'save',
            'dialog' => 'middle'
        ]);
    }

    /**
     * @return array
     * @throws SeeDbException|SeeException
     */
    public function save(): array
    {
        $data = See::request()->post();
        unset($data['id']);


        if (empty($data)) {
            return $this->fail(Operate::saveParameterNull());
        }

        /**
         * 返回自增主键
         */
        $result = $this->db()->save($data);

        if ($result) {
            return $this->saveSuccess($result);
        }

        return $this->saveFail();
    }

    /**
     * @return array
     * @throws SeeDbException|SeeException
     */
    public function delete(): array
    {
        $id = See::request()->param('id');

        if (empty($id)) {
            return $this->fail(Operate::required());
        }

        if (is_numeric($id)) {
            $data = $this->db()->find(intval($id));
            if (empty($data)) {
                return $this->fail(Operate::notFoundData());
            }
        }

        if (is_string($id)) {
            $id = explode(',', $id);
        }

        $res = $this->db()->delete($id);

        if ($res) {
            return $this->success($res, sprintf(SeeLang::operate('del_success') . ':%s', $res));
        }

        return $this->fail(SeeLang::operate('del_fail'));
    }

    /**
     * @return array
     * @throws SeeDbException|SeeException
     */
    public function patch(): array
    {
        $id = See::request()->post('id');
        $field = See::request()->post('field');
        $value = See::request()->post('value');

        if (empty($id)) {
            return $this->fail(SeeLang::operate('parameter_error'));
        }

        if (empty($field)) {
            return $this->fail(SeeLang::operate('parameter_error'));
        }

        if ($value === '' || $value === 'null' || $value === null) {
            return $this->fail(SeeLang::operate('parameter_error'));
        }

        $result = $this->db()->save([
            'id' => $id,
            $field => $value
        ]);

        if ($result) {
            return $this->saveSuccess();
        }

        return $this->fail(SeeLang::operate('save_error'));
    }

    /**
     * 新增
     * @return array
     */
    protected function controls(): array
    {
        return [];
    }

    /**
     * 编辑
     * @return array
     */
    protected function editControls(): array
    {
        return $this->controls();
    }

    /**
     * 查看
     * @return array
     */
    protected function readControls(): array
    {
        return $this->controls();
    }

    /**
     * 工具栏
     * @return string[]
     */
    protected function leftToolbars(): array
    {
        return ['create', 'del'];
    }

    protected function rightToolbars(): array
    {
        return ['filter', 'print', 'exports'];
    }

    /**
     * 查询
     * @return array
     */
    protected function query(): array
    {
        return [];
    }

    /**
     * 表格列
     * @return array
     */
    protected function columns(): array
    {
        return [];
    }

    /**
     * 操作列
     * @return string[]
     */
    protected function actions(): array
    {
        return ['read', 'edit', 'del'];
    }

    /**
     * 构建表单
     * @return Page
     */
    protected function builder(): Page
    {
        $page = new Page($this->pageTitle());

        $columns = $this->columns();
        if (empty($columns) && $this->table_name) {
            $data = parse_db_table($this->table_name);
            $columns = $data['columns'] ?? [];
        }

        $dictionary = [];
        if ($this->dictionary_name) {
            $dictionary = SeeLang::instance()->global($this->dictionary_name);
        }
        $dictionary = $dictionary ?: ($data['dictionary'] ?? '');

        $page->setDictionary($dictionary);
        $page->setActions($this->actions());
        $page->setColumns($columns);
        $page->setQuery($this->query());
        $page->setLeftToolbars($this->leftToolbars());
        $page->setRightToolbars($this->rightToolbars());
        $page->setRouteName(strtolower(pathinfo(static::class, PATHINFO_BASENAME)));

        return $page;
    }
}